package com.huishu.commons.utlis;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.impl.PublicClaims;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.huishu.commons.constant.Token;
import com.huishu.commons.exception.AuthenticationException;
import com.huishu.commons.exception.JwtException;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 *
 * @author ljj
 * @date 2021/4/9
 */
@Slf4j
public class JwtUtil {
    public static final String SECRET = "huishu_jwt_2023";

    private static final String ISSUER = "huishu-shop";

    public static String createUserToken(Long uid, String salt) {
        return createToken(uid, null, Token.USER_TIMEOUT, ISSUER, salt);
    }

    public static String createAdminUserToken(Long uid, String salt) {
        return createToken(null, uid, Token.USER_TIMEOUT, ISSUER, salt);
    }

    public static DecodedJWT verify(String token, HttpServletResponse response) {
        try {
            return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
        } catch (TokenExpiredException e) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            throw new AuthenticationException("token失效");
        } catch (JWTVerificationException | UnsupportedEncodingException e) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            log.warn("token verify exception", e);
            throw new JwtException("token校验失败");
        }
    }


    public static DecodedJWT verify(String token) {
        try {
            return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
        } catch (TokenExpiredException e) {
            return null;
        } catch (JWTVerificationException | UnsupportedEncodingException e) {
            log.warn("token verify exception", e);
            return null;
        }
    }

    private static String createToken(Long uid, Long adminUid, Long timeOut, String issuer, String salt) {
        String token;
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            Map<String, Object> heads = new HashMap<>(2);
            Date now = new Date();
            Date expiresTime = new Date(now.getTime() + timeOut);
            heads.put(PublicClaims.ALGORITHM, "HS256");
            heads.put(PublicClaims.TYPE, "JWT");
            token = JWT.create().withHeader(heads).withClaim("uid", uid)
                    .withClaim("adminUid", adminUid)
                    .withClaim("salt", salt)
                    .withIssuer(issuer).withIssuedAt(now).withExpiresAt(expiresTime)
                    .sign(algorithm);
        } catch (JWTCreationException | UnsupportedEncodingException exception) {
            throw new JwtException("JWT生成Token失败");
        }
        return token;
    }
}
